#!/usr/bin/perl
use strict;
use warnings;

use lib '../lib';
use lib '../extlib';
use ChessLike::Board;
use ChessLike::GamePiece;

use Test::Exception;
use Test::More 'no_plan';

######################
### Initial Layout ###
######################

print "\n[ Initial Layout ]\n";

###### GAME PLAN ######
# 01a # exception - empty tile: a1-a2
# 01b # exception - invalid move: b1-a3
# 01c # exception - on-spot rotation of an
#        unrotatable unit: b1>e
# 01d # exception - move + rotation of an unrotatable
#        unit: b1-a1>w
# 01* # basic move: b1-a1
# 02a # exception - wrong player: d4+c4
# 02* # basic capture: e6+f5
# 03a # exception - try to shoot and rotate: d4*f4>s
# 03* # basic shot: d4*f4
###### Confirm board layout
# 04a # exception - carrier move with all possible
#        links, forcing two opposing fliers onto the
#        same tile: b7-b6/a6,a6.1,a7,b7.1,c7
# 04b # exception - carrier moving without all unshared
#        links: a5-a4/a6,a6.1
# 04c # exception - carrier moving with illegal link:
#        a5-a4/a6,a6.1,a4,c7
# 04d # exception - carrier moving with non-existent
#        link: a5-a4/a6,a6.1,b6
# 04* # flier captures flier, forcing two opposing
#        fliers onto the same tile: c7+c6
# 05a # exception - try to do a move other than shoot
#        flier: a1-a2
# 05* # shoot flier on same square: c6*c6.1
# 06* # carrier move with all possible links,
#        forcing a friendly flier to dock:
#        b7-b6/a6,a6.1,a7,b7.1
# 07*   move carrier with linked flier into a boundary:
#        b2-a2
# 08* # capture a unit underneath enemy flier: b5+c4
# 09* # as a sanity check against the exception that
#        forces opposing fliers to not occupy the same
#        space, do NOT not capture the unit underneath
#        the flier just yet.
#       capture a carrier and kill linked fliers: b4+a5
# 10a # exception - flier tries to cross boundary: a6-f6
# 10* # flier captures enemy ground and occupies space
#        with friendly flier: a6+a5
# 11* # flier shoots ground unit underneath it: c4.1*c4
###### Confirm board layout
# 12* # move + rotate: d4-e4>w
# 13a # exception - try to rotate 360 degrees on the
#        spot: f1>w
# 13b # exception - rotation action with undef direction:
#        f1>undef
# 13* # rotate on the spot: f1>n
# 14* # capture + rotate for checkmate: e4+f5>n
###### Confirm board layout

print "\n"
 . '  #########################' . "\n"
 . '7 # f # cf# f #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # ff#   # FF#   # p #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # c # p # C #   #   # P #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   # p #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 #   # K #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

## Board initialization
    
my $board = ChessLike::Board->new(
    'x-tiles' => 6, 'y-tiles' => 7 );
my ( $action, @actions, @legal_actions,
     @results, $gamepieces_ref, $teams_ref,
     $directions_ref, );

## Gamepiece initialization

my $king = ChessLike::GamePiece->new(
   'name'         => 'King',
   'move-vectors' => [ [ -1, 1, 1 ], [ 0, 1, 1 ], [ 1, 1, 1 ],
                       [ -1, 0, 1 ],              [ 1, 0, 1 ],
                       [ -1,-1, 1 ], [ 0,-1, 1 ], [ 1,-1, 1 ] ],
);

my $pawn = ChessLike::GamePiece->new(
   'name'         => 'Pawn',
   'move-vectors' => [ [ -1, 1, 1 ], [ 1, 1, 1 ] ],
);

my $carrier = ChessLike::GamePiece->new(
   'name'         => 'Carrier',
   'move-vectors' => [ [ -1, 1, 1 ], [ 0, 1, 1 ], [ 1, 1, 1 ],
                       [ -1, 0, 1 ],              [ 1, 0, 1 ],
                       [ -1,-1, 1 ], [ 0,-1, 1 ], [ 1,-1, 1 ] ],
   'proxy-move-field'   => [ 3, 3, 2, 2 ],
   'carries-units' => 'Flier',
);

my $flier = ChessLike::GamePiece->new(
   'name'         => 'Flier',
   'move-vectors' => [ [ -1, 1, 99 ], [ 0, 1, 99 ], [ 1, 1, 99 ],
                       [ -1, 0, 99 ],               [ 1, 0, 99 ],
                       [ -1,-1, 99 ], [ 0,-1, 99 ], [ 1,-1, 99 ] ],
   'shot-vectors' => [ [ 0, 0, 1 ] ],
   'is-flying'    => 1,
   'requires-units'    => 'Carrier',
);

my $artillery = ChessLike::GamePiece->new(
   'name'         => 'Artillery',
   'move-vectors' => [ [ -1, 1, 1 ], [ 0, 1, 1 ], [ 1, 1, 1 ],
                       [ -1, 0, 1 ],              [ 1, 0, 1 ],
                       [ -1,-1, 1 ], [ 0,-1, 1 ], [ 1,-1, 1 ] ],
   'can-rotate'   => 1,
   'shot-vectors' => [ [ -1, 1, 2 ], [ 0, 1, 2 ], [ 1, 1, 2 ] ],
);

## Gamepiece positioning

$board->add(
   'b1',
   'gamepiece' => $king,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'f1',
   'gamepiece' => $artillery,
   'direction' => 'w',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'a2',
   'gamepiece' => $flier,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'b2',
   'gamepiece' => $carrier,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'a4',
   'gamepiece' => $flier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'b4',
   'gamepiece' => $pawn,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'c4',
   'gamepiece' => $pawn,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'c4',
   'gamepiece' => $flier,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'd4',
   'gamepiece' => $artillery,
   'direction' => 'e',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'f4',
   'gamepiece' => $pawn,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'a5',
   'gamepiece' => $carrier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'b5',
   'gamepiece' => $pawn,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'c5',
   'gamepiece' => $carrier,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'f5',
   'gamepiece' => $pawn,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'a6',
   'gamepiece' => $flier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'a6',
   'gamepiece' => $flier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'c6',
   'gamepiece' => $flier,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'c6',
   'gamepiece' => $flier,
   'direction' => 'n',
   'team'      => 0,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'e6',
   'gamepiece' => $pawn,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'a7',
   'gamepiece' => $flier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'b7',
   'gamepiece' => $carrier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'b7',
   'gamepiece' => $flier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'c7',
   'gamepiece' => $flier,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'e7',
   'gamepiece' => $pawn,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

$board->add(
   'f7',
   'gamepiece' => $king,
   'direction' => 's',
   'team'      => 1,
   'graphic'   => '3D_spazztacular_graphic.gif',
);

#################
### Action 01 ###
#################

print "\n[ Action 01a ] a1-a2 [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'a1',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'a2',
    'target-index' => 0,
    'direction' => undef,
);

dies_ok { $board->apply_action( $action ) }
         "[ 01a ] exception, empty tile";

is( $action->to_string(),
    'a1-a2', "[ 01a ] to_string" );
is( $action->to_string( 1 ),
    'a1-a2', "[ 01a ] to_string, truncated" );

print "\n[ Action 01b ] b1-a3 [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'b1',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'a3',
    'target-index' => 0,
    'direction' => undef,
);

dies_ok { $board->apply_action( $action ) }
         "[ 01b ] exception, invalid move";

is( $action->to_string(),
    'b1-a3', "[ 01b ] to_string" );
is( $action->to_string( 1 ),
    'b1-a3', "[ 01b ] to_string, truncated" );

print "\n[ Action 01c ] b1>e [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'b1',
    'index' => 0,
    'type' => 'rotation',
    'target-tile' => 'b1',
    'target-index' => 0,
    'direction' => 'e',
);

dies_ok { $board->apply_action( $action ) }
         "[ 01c ] exception, on-spot rotation of an unrotatable unit";

is( $action->to_string(),
    'b1>e', "[ 01c ] to_string" );
is( $action->to_string( 1 ),
    'b1>', "[ 01c ] to_string, truncated" );

print "\n[ Action 01d ] b1-a1>w [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'b1',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'a1',
    'target-index' => 0,
    'direction' => 'w',
);

dies_ok { $board->apply_action( $action ) }
         "[ 01d ] exception, move + rotation of an unrotatable unit";

is( $action->to_string(),
    'b1-a1>w', "[ 01d ] to_string" );
is( $action->to_string( 1 ),
    'b1-a1', "[ 01d ] to_string, truncated" );

print "\n[ Action 01* ] b1-a1\n";

@legal_actions = $board->legal_actions( 'b1', 0 );
@actions = grep { $_->to_string( 1 ) eq 'b1-a1' } @legal_actions;
is( @actions, 1, "[ 01* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'b1', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 01* ] gamepiece removed' );

$gamepieces_ref = $board->get_tile_contents( 'a1', 'gamepieces' );
is( @{ $gamepieces_ref }, 1, '[ 01* ] gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'King', '[ 01* ] gamepiece added: name' );

is( $action->to_string(),
    'b1-a1', "[ 01* ] to_string" );
is( $action->to_string( 1 ),
    'b1-a1', "[ 01* ] to_string, truncated" );

is( @results, 1, "[ 01* ] results, array size" );
is( "@{ $results[0] }",
    'move b1 0 a1 0', "[ 01* ] result 1" );

print "\n"
 . '  #########################' . "\n"
 . '7 # f # cf# f #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # ff#   # FF#   # p #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # c # p # C #   #   # P #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   # p #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 02 ###
#################

#TODO: print "\n[ Action 02a ] d4+c4 [invalid]\n";

# $action = ChessLike::Action->new(
#     'tile' => 'd4',
#     'index' => 0,
#     'type' => 'capture',
#     'target-tile' => 'c4',
#     'target-index' => 0,
#     'direction' => undef,
# );

# dies_ok { $board->apply_action( $action ) }
#          "[ 02a ] exception, wrong player";

print "\n[ Action 02* ] e6+f5\n";

@legal_actions = $board->legal_actions( 'e6', 0 );
@actions = grep { $_->to_string( 1 ) eq 'e6+f5' } @legal_actions;
is( @actions, 1, "[ 02* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'e6', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 02* ] gamepiece removed' );

( $gamepieces_ref, $teams_ref )
    = $board->get_tile_contents( 'f5', 'gamepieces', 'teams' );
is( @{ $gamepieces_ref }, 1, '[ 02* ] gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Pawn', '[ 02* ] gamepiece added: name' );
is( $teams_ref->[0], 1, '[ 02* ] gamepiece added: team' );

is( $action->to_string(),
    'e6+f5', "[ 02* ] to_string" );
is( $action->to_string( 1 ),
    'e6+f5', "[ 02* ] to_string, truncated" );

is( @results, 2, "[ 02* ] results, array size" );
is( "@{ $results[0] }",
    'remove f5 0', "[ 02* ] result 1" );
is( "@{ $results[1] }",
    'move e6 0 f5 0', "[ 02* ] result 2" );

print "\n"
 . '  #########################' . "\n"
 . '7 # f # cf# f #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # ff#   # FF#   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # c # p # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   # p #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 03 ###
#################

print "\n[ Action 03a ] d4*f4>s [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'd4',
    'index' => 0,
    'type' => 'shot',
    'target-tile' => 'f4',
    'target-index' => 0,
    'direction' => 's',
);

dies_ok { $board->apply_action( $action ) }
          "[ 03a ] exception, try to shoot and rotate";

is( $action->to_string(),
    'd4*f4>s', "[ 03a ] to_string" );
is( $action->to_string( 1 ),
    'd4*f4', "[ 03a ] to_string, truncated" );

print "\n[ Action 03* ] d4*f4\n";

@legal_actions = $board->legal_actions( 'd4', 0 );
@actions = grep { $_->to_string( 1 ) eq 'd4*f4' } @legal_actions;
is( @actions, 1, "[ 03* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'f4', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 03* ] target gamepiece removed' );

$gamepieces_ref = $board->get_tile_contents( 'd4', 'gamepieces' );
is( @{ $gamepieces_ref }, 1, '[ 03* ] gamepiece stationary: array size' );
is( $gamepieces_ref->[0]->name(), 'Artillery', '[ 03* ] gamepiece stationary: name' );

is( $action->to_string(),
    'd4*f4', "[ 03* ] to_string" );
is( $action->to_string( 1 ),
    'd4*f4', "[ 03* ] to_string, truncated" );

is( @results, 1, "[ 03* ] results, array size" );
is( "@{ $results[0] }",
    'remove f4 0', "[ 03* ] result 1" );

print "\n"
 . '  #########################' . "\n"
 . '7 # f # cf# f #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # ff#   # FF#   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # c # p # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 04 ###
#################

print "\n[ Action 04a ] b7-b6/a6,a6.1,a7,b7.1,c7 [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'b7',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'b6',
    'target-index' => 0,
    'direction' => undef,
    'links' => [ 'a6', 'a6.1', 'a7', 'b7.1', 'c7' ]
);

dies_ok { $board->apply_action( $action ) }
    "[ 04a ] exception, flier blocked from moving with carrier";

is( $action->to_string(),
    'b7-b6/a6,a6.1,a7,b7.1,c7', "[ 04a ] to_string" );
is( $action->to_string( 1 ),
    'b7-b6', "[ 04a ] to_string, truncated" );

print "\n[ Action 04b ] a5-a4/a6,a6.1 [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'a5',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'a4',
    'target-index' => 0,
    'direction' => undef,
    'links' => [ 'a6', 'a6.1' ]
);

dies_ok { $board->apply_action( $action ) }
    "[ 04b ] exception, carrier moving without all unshared links";

is( $action->to_string(),
    'a5-a4/a6,a6.1', "[ 04b ] to_string" );
is( $action->to_string( 1 ),
    'a5-a4', "[ 04b ] to_string, truncated" );

print "\n[ Action 04c ] a5-a4/a6,a6.1,a4,c7 [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'a5',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'a4',
    'target-index' => 0,
    'direction' => undef,
    'links' => [ 'a6', 'a6.1', 'a4', 'c7' ]
);

dies_ok { $board->apply_action( $action ) }
    "[ 04c ] exception, carrier moving with illegal link";

is( $action->to_string(),
    'a5-a4/a4,a6,a6.1,c7', "[ 04c ] to_string" );
is( $action->to_string( 1 ),
    'a5-a4', "[ 04c ] to_string, truncated" );

print "\n[ Action 04d ] a5-a4/a6,a6.1,a4,b6 [invalid]\n";

$action = ChessLike::Action->new(
    'tile' => 'a5',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'a4',
    'target-index' => 0,
    'direction' => undef,
    'links' => [ 'a6', 'a6.1', 'a4', 'b6' ]
);

dies_ok { $board->apply_action( $action ) }
    "[ 04d ] exception, carrier moving with nonexistent link";

is( $action->to_string(),
    'a5-a4/a4,a6,a6.1,b6', "[ 04d ] to_string" );
is( $action->to_string( 1 ),
    'a5-a4', "[ 04d ] to_string, truncated" );

print "\n[ Action 04* ] c7+c6\n";

@legal_actions = $board->legal_actions( 'c7', 0 );
@actions = grep { $_->to_string( 1 ) eq 'c7+c6' } @legal_actions;
is( @actions, 1, "[ 04* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'c7', 'gamepieces');
is( @{ $gamepieces_ref }, 0, '[ 04* ] c7 gamepiece removed' );

( $gamepieces_ref, $teams_ref ) = $board->get_tile_contents(
    'c6', 'gamepieces', 'teams' );
is( @{ $gamepieces_ref }, 2, '[ 04* ] gampiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Flier', '[ 04* ] gamepiece added: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 04* ] gamepiece added: name2' );
is( $teams_ref->[0], 0, '[ 04* ] gamepiece added: team1' );
is( $teams_ref->[1], 1, '[ 04* ] gamepiece added: team2' );

is( $action->to_string(),
    'c7+c6', "[ 04* ] to_string" );
is( $action->to_string( 1 ),
    'c7+c6', "[ 04* ] to_string, truncated" );

is( @results, 2, "[ 04* ] results, array size" );
is( "@{ $results[0] }",
    'remove c6 0', "[ 04* ] result 1" );
is( "@{ $results[1] }",
    'move c7 0 c6 1', "[ 04* ] result 2" );

print "\n"
 . '  #########################' . "\n"
 . '7 # f # cf#   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # ff#   # Ff#   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # c # p # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 05 ###
#################

# TODO: exception.  Only one legal move available
#print "\n[ Action 05a ] a1-a2\n";

print "\n[ Action 05* ] c6*c6.1\n";

@legal_actions = $board->legal_actions( 'c6', 0 );
@actions = grep { $_->to_string( 1 ) eq 'c6*c6.1' } @legal_actions;
is( @actions, 1, "[ 05* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

( $gamepieces_ref, $teams_ref ) = $board->get_tile_contents(
    'c6', 'gamepieces', 'teams' );
is( @{ $gamepieces_ref }, 1, '[ 05* ] c6 gamepiece removed: array size' );
is( $gamepieces_ref->[0]->name(), 'Flier', '[ 05* ] c6 gamepiece removed: name' );
is( $teams_ref->[0], 0, '[ 05* ] c6 gamepiece removed: team' );

is( $action->to_string(),
    'c6*c6.1', "[ 05* ] to_string" );
is( $action->to_string( 1 ),
    'c6*c6.1', "[ 05* ] to_string, truncated" );

is( @results, 1, "[ 05* ] results, array size" );
is( "@{ $results[0] }",
    'remove c6 1', "[ 05* ] result 1" );

print "\n"
 . '  #########################' . "\n"
 . '7 # f # cf#   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # ff#   # F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # c # p # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 06 ###
#################

print "\n[ Action 06* ] b7-b6/a6,a6.1,a7,b7.1\n";

@legal_actions = $board->legal_actions( 'b7', 0 );
@actions = grep { $_->to_string( 1 ) eq 'b7-b6' } @legal_actions;
is( @actions, 1, "[ 06* ] legal" );
$action = $actions[0];
$action->upgrade_link( 'a6' );
$action->upgrade_link( 'a6.1' );

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'a7', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 06* ] a7 gamepiece removed' );

$gamepieces_ref = $board->get_tile_contents( 'b7', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 06* ] b7 gamepieces removed' );

$gamepieces_ref = $board->get_tile_contents( 'a6', 'gamepieces' );
is( @{ $gamepieces_ref }, 1, '[ 06* ] a6 gamepiece moved: array size' );
is( $gamepieces_ref->[0]->name(), 'Flier', '[ 06* ] a6 gamepiece moved: name' );

$gamepieces_ref = $board->get_tile_contents( 'b6', 'gamepieces' );
is( @{ $gamepieces_ref }, 2, '[ 06* ] b6 gamepieces moved: array size' );
is( $gamepieces_ref->[0]->name(), 'Carrier', '[ 06* ] b6 gamepieces moved: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 06* ] b6 gamepieces moved: name2' );

$gamepieces_ref = $board->get_tile_contents( 'a5', 'gamepieces' );
is( @{ $gamepieces_ref }, 3, '[ 06* ] a5 gamepieces moved: array size' );
is( $gamepieces_ref->[0]->name(), 'Carrier', '[ 06* ] a5 gamepieces moved: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 06* ] a5 gamepieces moved: name2' );
is( $gamepieces_ref->[2]->name(), 'Flier', '[ 06* ] a5 gamepieces moved: name2' );

is( $action->to_string(),
    'b7-b6/a6,a6.1,a7,b7.1', "[ 06* ] to_string" );
is( $action->to_string( 1 ),
    'b7-b6', "[ 06* ] to_string, truncated" );

is( @results, 5, "[ 06* ] results, array size" );
is( "@{ $results[0] }",
    'move b7 0 b6 0', "[ 06* ] result 1" );
is( "@{ $results[1] }",
    'move a6 0 a5 1', "[ 06* ] result 2" );
is( "@{ $results[2] }",
    'move a6 1 a5 2', "[ 06* ] result 3" );
is( "@{ $results[3] }",
    'move a7 0 a6 0', "[ 06* ] result 4" );
is( "@{ $results[4] }",
    'move b7 1 b6 1', "[ 06* ] result 5" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # f # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 #cff# p # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # F # C #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 07 ###
#################

print "\n[ Action 07* ] b2-a2/a2\n";

@legal_actions = $board->legal_actions( 'b2', 0 );
@actions = grep { $_->to_string( 1 ) eq 'b2-a2' } @legal_actions;
is( @actions, 1, "[ 07* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'b2', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 07* ] b2 gamepiece removed: array size' );

$gamepieces_ref = $board->get_tile_contents( 'a2', 'gamepieces' );

is( @{ $gamepieces_ref }, 2, '[ 07* ] a2 gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Carrier', '[ 07* ] a2 gamepiece added: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 07* ] a2 gamepiece added: name2' );

is( $action->to_string(),
    'b2-a2/a2', "[ 07* ] to_string" );
is( $action->to_string( 1 ),
    'b2-a2', "[ 07* ] to_string, truncated" );

is( @results, 2, "[ 07* ] results, array size" );
is( "@{ $results[0] }",
    'move b2 0 a2 0', "[ 07* ] result 1" );
is( "@{ $results[1] }",
    'move a2 0 a2 1', "[ 07* ] result 2" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # f # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 #cff# p # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # PF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 08 ###
#################

print "\n[ Action 08* ] b5+c4\n";

@legal_actions = $board->legal_actions( 'b5', 0 );
@actions = grep { $_->to_string( 1 ) eq 'b5+c4' } @legal_actions;
is( @actions, 1, "[ 08* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'b5', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 08* ] b5 gamepiece removed' );

( $gamepieces_ref, $teams_ref ) = $board->get_tile_contents(
    'c4', 'gamepieces', 'teams' );
is( @{ $gamepieces_ref }, 2, '[ 08* ] c4 gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Pawn', '[ 08* ] c4 gamepiece added: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 08* ] c4 gamepiece added: name2' );
is( $teams_ref->[0], 1, '[ 08* ] c4 gamepiece added: team' );
is( $teams_ref->[1], 0, '[ 08* ] c4 gamepiece added: team' );

is( $action->to_string(),
    'b5+c4', "[ 08* ] to_string" );
is( $action->to_string( 1 ),
    'b5+c4', "[ 08* ] to_string, truncated" );

is( @results, 2, "[ 08* ] results, array size" );
is( "@{ $results[0] }",
    'remove c4 0', "[ 08* ] result 1" );
is( "@{ $results[1] }",
    'move b5 0 c4 0', "[ 08* ] result 2" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # f # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 #cff#   # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 # f # P # pF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 09 ###
#################

print "\n[ Action 09* ] b4+a5\n";

@legal_actions = $board->legal_actions( 'b4', 0 );
@actions = grep { $_->to_string( 1 ) eq 'b4+a5' } @legal_actions;
is( @actions, 1, "[ 09* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'b4', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 09* ] b4 gamepiece removed: array size' );

$gamepieces_ref = $board->get_tile_contents( 'a5', 'gamepieces' );
is( @{ $gamepieces_ref }, 2, '[ 09* ] a5 gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Pawn', '[ 09* ] a5 gamepiece added: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 09* ] a5 gamepiece added: name2' );

$gamepieces_ref = $board->get_tile_contents( 'a4', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 09* ] a4 linked gamepiece removed: array size' );

$gamepieces_ref = $board->get_tile_contents( 'a6', 'gamepieces' );
is( @{ $gamepieces_ref }, 1, '[ 09* ] a6 linked gamepiece not removed: array size' );
is( $gamepieces_ref->[0]->name(), 'Flier', '[ 09* ] a6 linked gamepiece not removed: name' );

is( $action->to_string(),
    'b4+a5', "[ 09* ] to_string" );
is( $action->to_string( 1 ),
    'b4+a5', "[ 09* ] to_string, truncated" );

is( @results, 4, "[ 09* ] results, array size" );
is( "@{ $results[0] }",
    'remove a5 0', "[ 09* ] result 1" );
is( "@{ $results[1] }",
    'remove a4 0', "[ 09* ] result 2" );
is( "@{ $results[2] }",
    'remove a5 0', "[ 09* ] result 3" );
is( "@{ $results[3] }",
    'move b4 0 a5 0', "[ 09* ] result 4" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 # f # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # Pf#   # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 #   #   # pF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 10 ###
#################

print "\n[ Action 10a ] a6-f6\n";

$action = ChessLike::Action->new(
    'tile' => 'a6',
    'index' => 0,
    'type' => 'move',
    'target-tile' => 'f6',
    'target-index' => 0,
    'direction' => undef,
);

dies_ok { $board->apply_action( $action ) }
         "[ 10a ] exception, flier crosses boundary";

is( $action->to_string(),
    'a6-f6', "[ 10a ] to_string" );
is( $action->to_string( 1 ),
    'a6-f6', "[ 10a ] to_string, truncated" );

print "\n[ Action 10* ] a6+a5\n";

@legal_actions = $board->legal_actions( 'a6', 0 );
@actions = grep { $_->to_string( 1 ) eq 'a6+a5' } @legal_actions;
is( @actions, 1, "[ 10* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'a6', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 10* ] a6 gamepiece removed: array size' );

$gamepieces_ref = $board->get_tile_contents( 'a5', 'gamepieces' );
is( @{ $gamepieces_ref }, 2, '[ 10* ] a6 gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Flier', '[ 10* ] a6 gamepiece added: name1' );
is( $gamepieces_ref->[1]->name(), 'Flier', '[ 10* ] a6 gamepiece added: name2' );

is( $action->to_string(),
    'a6+a5', "[ 10* ] to_string" );
is( $action->to_string( 1 ),
    'a6+a5', "[ 10* ] to_string, truncated" );

is( @results, 2, "[ 10* ] results, array size" );
is( "@{ $results[0] }",
    'remove a5 0', "[ 10* ] result 1" );
is( "@{ $results[1] }",
    'move a6 0 a5 1', "[ 10* ] result 2" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 #   # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # ff#   # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 #   #   # pF# A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 11 ###
#################

print "\n[ Action 11* ] c4.1*c4\n";

@legal_actions = $board->legal_actions( 'c4', 1 );
@actions = grep { $_->to_string( 1 ) eq 'c4.1*c4' } @legal_actions;
is( @actions, 1, "[ 11* ] legal" );
$action = $actions[0];

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'c4', 'gamepieces' );
is( @{ $gamepieces_ref }, 1, '[ 11* ] c4 gamepiece removed: array size' );
is( $gamepieces_ref->[0]->name(), 'Flier', '[ 11* ] c4 gamepiece removed: name' );

is( $action->to_string(),
    'c4.1*c4', "[ 11* ] to_string" );
is( $action->to_string( 1 ),
    'c4.1*c4', "[ 11* ] to_string, truncated" );

is( @results, 1, "[ 11* ] results, array size" );
is( "@{ $results[0] }",
    'remove c4 0', "[ 11* ] result 1" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 #   # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # ff#   # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 #   #   # F # A>#   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 12 ###
#################

print "\n[ Action 12* ] d4-e4>w\n";

@legal_actions = $board->legal_actions( 'd4', 0 );
@actions = grep { $_->to_string( 1 ) eq 'd4-e4' } @legal_actions;
is( @actions, 1, "[ 12* ] destination legal" );
$action = $actions[0];
ok( $action->set_direction( 'w' ), "[ 12* ] direction legal" );

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'd4', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 12* ] d4 gamepiece removed: array size' );
( $gamepieces_ref, $directions_ref ) =
    $board->get_tile_contents( 'e4', 'gamepieces', 'directions' );
is( @{ $gamepieces_ref }, 1, '[ 12* ] e4 gamepiece added: array size' );
is( $gamepieces_ref->[0]->name(), 'Artillery',
    '[ 12* ] e4 gamepiece added: name' );
is( $directions_ref->[0], 'w',
    '[ 12* ] e4 gamepiece added: direction' );

is( $action->to_string(),
    'd4-e4>w', "[ 12* ] to_string" );
is( $action->to_string( 1 ),
    'd4-e4', "[ 12* ] to_string, truncated" );

is( @results, 2, "[ 12* ] results, array size" );
is( "@{ $results[0] }",
    'rotate d4 0 w', "[ 12* ] result 0" );
is( "@{ $results[1] }",
    'move d4 0 e4 0', "[ 12* ] result 1" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 #   # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # ff#   # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 #   #   # F #   #<A #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '1 # K #   #   #   #   #<a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 13 ###
#################

print "\n[ Action 13a ] f1>w\n";

$action = ChessLike::Action->new(
    'tile' => 'f1',
    'index' => 0,
    'type' => 'rotation',
    'target-tile' => 'f1',
    'target-index' => 0,
    'direction' => 'w',
);

dies_ok { $board->apply_action( $action ) }
         "[ 13a ] exception, 360 degree on-spot rotation";

is( $action->to_string(),
    'f1>w', "[ 13a ] to_string" );
is( $action->to_string( 1 ),
    'f1>', "[ 13a ] to_string, truncated" );

print "\n[ Action 13b ] f1>undef\n";

$action = ChessLike::Action->new(
    'tile' => 'f1',
    'index' => 0,
    'type' => 'rotation',
    'target-tile' => 'f1',
    'target-index' => 0,
    'direction' => undef,
);

dies_ok { $board->apply_action( $action ) }
         "[ 13b ] exception, rotation action with undef direction";

is( $action->to_string(),
    'f1>', "[ 13b ] to_string" );
is( $action->to_string( 1 ),
    'f1>', "[ 13b ] to_string, truncated" );

print "\n[ Action 13* ] f1>n\n";

@legal_actions = $board->legal_actions( 'f1', 0 );
@actions = grep { $_->to_string( 1 ) eq 'f1>' } @legal_actions;
is( @actions, 1, "[ 13* ] destination legal" );
$action = $actions[0];
ok( $action->set_direction( 'n' ), "[ 13* ] direction legal" );

@results = $board->apply_action( $action );

( $gamepieces_ref, $teams_ref, $directions_ref ) =
    $board->get_tile_contents( 'f1', 'gamepieces', 'teams', 'directions' );
is( @{ $gamepieces_ref }, 1, '[ 13* ] f1 gamepiece rotated: array size' );
is( $gamepieces_ref->[0]->name(), 'Artillery',
    '[ 13* ] f1 gamepiece rotated: name' );
is( $teams_ref->[0], 1, '[ 13* ] f1 gamepiece rotated: team' );
is( $directions_ref->[0], 'n',
    '[ 13* ] f1 gamepiece rotated: direction' );

is( $action->to_string(),
    'f1>n', "[ 13* ] to_string" );
is( $action->to_string( 1 ),
    'f1>', "[ 13* ] to_string, truncated" );

is( @results, 1, "[ 13* ] results, array size" );
is( "@{ $results[0] }",
    'rotate f1 0 n', "[ 13* ] result 1" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 #   # cf# F #   #   #   #' . "\n"
 . '  #########################   K = King' . "\n"
 . '5 # ff#   # C #   #   # p #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 #   #   # F #   #<A #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  ######################^##' . "\n"
 . '1 # K #   #   #   #   # a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

#################
### Action 14 ###
#################

print "\n[ Action 14* ] e4+f5>n\n";

@legal_actions = $board->legal_actions( 'e4', 0 );
@actions = grep { $_->to_string( 1 ) eq 'e4+f5' } @legal_actions;
is( @actions, 1, "[ 14* ] destination legal" );
$action = $actions[0];
ok( $action->set_direction( 'n' ), "[ 14* ] direction legal" );

@results = $board->apply_action( $action );

$gamepieces_ref = $board->get_tile_contents( 'e4', 'gamepieces' );
is( @{ $gamepieces_ref }, 0, '[ 14* ] e4 gamepiece removed: array size' );
( $gamepieces_ref, $teams_ref, $directions_ref ) =
    $board->get_tile_contents( 'f5', 'gamepieces', 'teams', 'directions' );
is( @{ $gamepieces_ref }, 1, '[ 14* ] f5 gamepiece captured: array size' );
is( $gamepieces_ref->[0]->name(), 'Artillery',
    '[ 14* ] f1 gamepiece captured: name' );
is( $teams_ref->[0], 0, '[ 14* ] f1 gamepiece captured: team' );
is( $directions_ref->[0], 'n',
    '[ 14* ] f1 gamepiece captured: direction' );

is( $action->to_string(),
    'e4+f5>n', "[ 14* ] to_string" );
is( $action->to_string( 1 ),
    'e4+f5', "[ 14* ] to_string, truncated" );

is( @results, 3, "[ 14* ] results, array size" );
is( "@{ $results[0] }",
    'rotate e4 0 n', "[ 14* ] result 1" );
is( "@{ $results[1] }",
    'remove f5 0', "[ 14* ] result 2" );
is( "@{ $results[2] }",
    'move e4 0 f5 0', "[ 14* ] result 3" );

print "\n"
 . '  #########################' . "\n"
 . '7 #   #   #   #   # p # k #   Uppercase = Player0' . "\n"
 . '  #########################   Lowercase = Player1' . "\n"
 . '6 #   # cf# F #   #   #   #' . "\n"
 . '  ######################^##   K = King' . "\n"
 . '5 # ff#   # C #   #   # A #   P = Pawn' . "\n"
 . '  #########################   C = Carrier' . "\n"
 . '4 #   #   # F #   #   #   #   F = Flier' . "\n"
 . '  #########################   A = Artillery' . "\n"
 . '3 #   #   #   #   #   #   #' . "\n"
 . '  #########################' . "\n"
 . '2 # CF#   #   #   #   #   #' . "\n"
 . '  ######################^##' . "\n"
 . '1 # K #   #   #   #   # a #' . "\n"
 . '  #########################' . "\n"
 . '    a   b   c   d   e   f' . "\n"
 . "\n";

## TODO: Test checkmate condition
